package com.kermel.andromeda.data;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.database.Cursor;

import com.kermel.andromeda.activities.countdown.add.AddCountdownTimerActivity;
import com.kermel.andromeda.activities.triggered.TriggeredAlarmActivity;
import com.kermel.andromeda.data.persistence.AndromedaDatabaseManager;
import com.kermel.andromeda.scheduler.AlarmScheduler;
import com.kermel.common.util.DateTimeUtils;

public class AlarmManager {
    public static final AlarmManager instance = new AlarmManager();
    public static final int DEFAULT_SNOOZE_TIME_DURATION_IN_MINUTES = 10;

    List<Alarm> alarms;
    AlarmScheduler alarmScheduler;
    long snoozeDurationInMilliseconds;
    
    private AlarmManager() {
        initAlarmsList();
        retrieveAlarmsFromDatabase();
    }
    
    void initAlarmsList() {
        alarms = new ArrayList<Alarm>();
    }
    
    protected void retrieveAlarmsFromDatabase() {
        Cursor cursor = AndromedaDatabaseManager.instance.retrieveAllAlarms();
        
        if (cursor != null) {
            int counter = 0;
            boolean more = true;
            
            while (more) {
                try {
                    Alarm alarm = AndromedaDatabaseManager.instance.getAlarm(cursor);
                    alarms.add(alarm);
                } catch (Exception e) {
                    System.err.println(String.format(".onClick - Error: %s", e.getMessage()));
                }
                
                more = cursor.moveToNext();
                counter++;
                
                if (counter++ > 1000)
                    more = false;
            }
        }
    }
    
    public int addAlarm(Alarm alarm, Context context) {
        int alarmNotificationID = Alarm.UNKNOWN_ALARM_NOTIFICATION_ID;
        
        if (alarm != null) {
            alarms.add(alarm);
            AndromedaDatabaseManager.instance.addAlarm(alarm);
            alarmNotificationID = scheduleAlarm(alarm, context);
        }
        
        return alarmNotificationID;
    }
    
    private void ensureSchedulerExists(Context context) {
        if (alarmScheduler == null)
            alarmScheduler = new AlarmScheduler(context);
    }
    
    // TODO: Reverse the order of the arguments
    protected int scheduleAlarm(Alarm alarm, Context context) {
        if (context == null)
            throw new IllegalArgumentException("Context cannot be null.");
        
        int alarmNotificationID = Alarm.UNKNOWN_ALARM_NOTIFICATION_ID;
        
        if (alarm != null) {
            ensureSchedulerExists(context);
            alarmNotificationID = alarmScheduler.scheduleAlarm(alarm, TriggeredAlarmActivity.class);
        }
        
        return alarmNotificationID;
    }
    
    public int scheduleCountdownTimer(Context context, CountdownTimer countdownTimer) {
        if (context == null)
            throw new IllegalArgumentException("Context cannot be null.");
        
        int alarmNotificationID = Alarm.UNKNOWN_ALARM_NOTIFICATION_ID;
        
        if (countdownTimer != null) {
            ensureSchedulerExists(context);
            alarmNotificationID = alarmScheduler.scheduleAlarm(countdownTimer, AddCountdownTimerActivity.class);
        }
        
        return alarmNotificationID;
    }
    
    public boolean removeAlarm(Alarm alarm) {
        boolean result = false;
        
        if (alarm != null) {
            result = alarms.remove(alarm);
            
            if (result) {
                // TODO: Getting an NPE here in some cases because alarmScheduler hasn't been initialized yet.
                // Unfortunately, we need a Context in order to create the AlarmScheduler; but I don't want to have to pass it in here.
                // What to do?
                //ensureSchedulerExists(context);
                AndromedaDatabaseManager.instance.deleteAlarm(alarm);
                alarmScheduler.removeStatusNotification(alarm.getAlarmNotificationID());
            }
        }
        
        return result;
    }
    
    void removeAllAlarms() {
        List<Alarm> allAlarms = new ArrayList<Alarm>(alarms);
        for (Alarm alarm : allAlarms) {
            removeAlarm(alarm); 
        }
    }
    
    public boolean resetAlarm(Alarm alarm, Context context) {
        boolean result = false;
        
        if (alarm != null) {
            if (alarm.enabled) {
                ensureSchedulerExists(context);
                alarmScheduler.removeStatusNotification(alarm.getAlarmNotificationID());
                scheduleAlarm(alarm, context);
                result = true;
            }
        }
        
        return result;
    }
    
    public int getAlarmCount() {
        return alarms.size();
    }
    
    public boolean areAnyAlarmsSet() {
        boolean result = false;
        
        for (Alarm alarm : alarms) {
            if (alarm.enabled) {
                result = true;
                break;
            }
        }
        
        return result;
    }
    
    public List<Alarm> getAlarms() {
        List<Alarm> listOfAlarms = new ArrayList<Alarm>(alarms);
        return listOfAlarms;
    }
    
    public Alarm getAlarmByIndex(int index) {
        Alarm alarm = null;
        
        if (alarms.isEmpty() == false) {
            if (isValidIndex(index)) {
                alarm = alarms.get(index);
            }
        }
        
        return alarm;
    }
    
    public boolean isValidIndex(int index) {
        boolean result = false;
        
        int numAlarms = alarms.size();
        result = index >= 0 && index < numAlarms;
        
        return result;
    }
    
    public boolean adjustAlarmToRetriggerAtEndOfSnoozePeriod(Alarm alarm, Context context) {
        boolean wasAdjusted = false;
        
        if (alarm != null) {
            adjustAlarmTriggerTimeForSnooze(alarm);
            resetAlarm(alarm, context);
            wasAdjusted = true;
        }
        
        return wasAdjusted;
    }
    
    private void adjustAlarmTriggerTimeForSnooze(Alarm alarm) {
        long originalTriggerTime = alarm.triggerTime;
        int snoozeDurationInMilliseconds = calculateSnoozeDurationInMilliseconds();
        long adjustedTriggerTime = DateTimeUtils.adjustDateTime(originalTriggerTime, snoozeDurationInMilliseconds);
        alarm.triggerTime = adjustedTriggerTime;
    }
    
    protected int calculateSnoozeDurationInMilliseconds() {
        int snoozeDurationInMilliseconds = 30 * 1000; //(int)DateTimeUtils.minutesToMilliseconds(DEFAULT_SNOOZE_TIME_DURATION_IN_MINUTES);
        return snoozeDurationInMilliseconds;
    }
    
}
